/**
 * 滑动窗口
 * 给定一个字符串 s ，请你找出其中不含有重复字符的 最长子串 的长度
 * 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc"，所以其长度为 3。
 * 测试案例：1）空串  2）'bbbbbb' 3）常规输入
 * @param {string} s
 * @return {number}
 */
console.time('test')
var lengthOfLongestSubstring = function (s) {
  if (typeof s !== 'string') {
    throw new TypeError('expect string, got' + typeof s)
  }
  const len = s.length
  // 字符串为空串直接返回 0
  if (len === 0) return 0
  // 用 map 来存储出现过的字符，每出现一个新字符，就设置这个字符为键，它的下标为关联的值
  // 出现重复的字符的时候，就更新关联的值为最新下标
  let map = new Map()
  // 设置 start 和 end 指针，end 为滑动窗口的右指针，并且始终指向当前遍历字符的下标
  // start 为滑动窗口的左指针，只有出现重复字符时，才会更新为上一个重复字符出现的下一个位置
  let start = 0, end = 0, max = 0
  while (end < len) {
    // 右指针指向的当前元素
    // const cur = s.charAt(end)
    // 出现重复字符，更新左指针
    if (map.has(s.charAt(end))) {
      start = Math.max(start, map.get(s.charAt(end)) + 1)
    }
    // 出现重复字符时更新，不出现重复字符则设置当前字符关联的值为右指针
    map.set(s.charAt(end), end)
    // 更新 max 最大不重复字符串长度的值
    max = Math.max(max, end - start + 1)
    // 右指针 + 1 继续滑动
    end++
  }
  return max
};
console.log(lengthOfLongestSubstring('b'))
console.log(lengthOfLongestSubstring('au'))
console.log(lengthOfLongestSubstring('abcabcd'))
console.timeEnd('test')
